package util;

import java.io.Serializable;
import java.util.List;

import org.apache.log4j.Logger;
import org.hibernate.Criteria;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.AnnotationConfiguration;

public class HibernateUtil implements Serializable
{
	// ---------------------------------------------------------------------------------------------

	private static final long						serialVersionUID	= 1L;
	private static final Logger					Log					= Logger.getLogger( HibernateUtil.class);
	private static final SessionFactory			staSessionFactory;

	private static final ThreadLocal<Session>	threadSession		= new ThreadLocal<Session>( );
	private static final ThreadLocal<Boolean>	threadRollback		= new ThreadLocal<Boolean>( );

	// ---------------------------------------------------------------------------------------------

	static
	{
		try
		{
			staSessionFactory = new AnnotationConfiguration( ).configure( ).buildSessionFactory( );
		}
		catch( Throwable ex)
		{
			Log.error( ex);
			throw new ExceptionInInitializerError( ex);
		}
	}

	// ---------------------------------------------------------------------------------------------

	public static void setError( )
	{
		threadRollback.set( true);
	}

	// ---------------------------------------------------------------------------------------------

	public static boolean openSession( )
	{
		threadRollback.set( false);
		try
		{
			if( threadSession.get( ) == null)
			{
				threadSession.set( staSessionFactory.openSession( ));
				Log.debug( "");
				return true;
			}
		}
		catch( Exception ex)
		{
			Log.error( "Session Not created ex=" + ex);
		}
		return false;
	}

	// ---------------------------------------------------------------------------------------------

	public static void closeSession( )
	{
		try
		{
			if( threadSession.get( ) != null)
			{
				threadSession.get( ).close( );
				Log.debug( "");
			}
		}
		catch( Exception ex)
		{
			Log.error( "Error ex=" + ex);
		}
		threadSession.set( null);
	}

	// ---------------------------------------------------------------------------------------------

	public static boolean beginTransaction( )
	{
		Log.debug( "");
		try
		{
			openSession( );
			if( threadSession.get( ) != null)
			{
				threadSession.get( ).beginTransaction( );
				return true;
			}
		}
		catch( Exception ex)
		{
			threadSession.set( null);
			Log.error( "Transaction Not Created ex=" + ex);
		}
		return false;
	}

	// ---------------------------------------------------------------------------------------------

	public static void commitOrRollback( )
	{
		Log.debug( "");

		if( threadSession.get( ) != null && threadSession.get( ).getTransaction( ) != null
					&& threadSession.get( ).getTransaction( ).isActive( ))
		{
			if( threadRollback.get( ))
			{
				threadRollback.set( false);
				try
				{
					threadSession.get( ).getTransaction( ).rollback( );
					Log.warn( "Rollback Done");
				}
				catch( Exception exr)
				{
					Log.error( "Rollback ex=" + exr);
				}
				closeSession( );
			}
			else
			{
				threadSession.get( ).getTransaction( ).commit( );

			}
		}
	}

	// ---------------------------------------------------------------------------------------------

	@SuppressWarnings("rawtypes")
	public static Criteria createCriteria( Class forClass)
	{
		Log.debug( "");

		openSession( );

		if( threadSession.get( ) != null)
		{
			return threadSession.get( ).createCriteria( forClass);
		}

		return null;
	}

	// ---------------------------------------------------------------------------------------------

	public static Object get( Class<?> theClass, Serializable serial)
	{
		Log.debug( theClass.getSimpleName( ) + " serial=" + serial);

		try
		{
			openSession( );

			if( threadSession.get( ).getTransaction( ).isActive( ))
			{
				Object object = threadSession.get( ).load( theClass, serial);
				return object;
			}
			else
			{
				beginTransaction( );
				Object object = threadSession.get( ).load( theClass, serial);
				commitOrRollback( );
				
				Log.debug( theClass.getSimpleName( ) + "=" + object);

				return object;
			}
		}
		catch( Exception ex)
		{
			Log.warn( "Ex=" + ex);
			threadRollback.set( true);
		}

		return null;
	}

	// ---------------------------------------------------------------------------------------------

	public static List<Object> getList( Criteria criteria)
	{
		Log.debug( "criteria=" + criteria);

		try
		{
			openSession( );

			if( threadSession.get( ).getTransaction( ).isActive( ))
			{
				List<Object> list = criteria.list( );
				return list;
			}
			else
			{
				beginTransaction( );
				List<Object> list = criteria.list( );
				commitOrRollback( );
				return list;
			}
		}
		catch( Exception ex)
		{
			Log.warn( "Ex=" + ex);
			threadRollback.set( true);
		}

		return null;
	}

	// ---------------------------------------------------------------------------------------------

	public static boolean saveOrUpdate( Object object)
	{
		Log.debug( object.getClass( ).getSimpleName( ));
		try
		{
			openSession( );

			if( threadSession.get( ).getTransaction( ).isActive( ))
			{
				threadSession.get( ).saveOrUpdate( object);
			}
			else
			{
				beginTransaction( );
				threadSession.get( ).saveOrUpdate( object);
				commitOrRollback( );
			}

			return true;
		}
		catch( Exception ex)
		{
			Log.warn( "Ex=" + ex);
			threadRollback.set( true);
		}

		return false;
	}

	// ---------------------------------------------------------------------------------------------

	public static boolean save( Object object)
	{
		Log.debug( object.getClass( ).getSimpleName( ));
		try
		{
			openSession( );

			if( threadSession.get( ).getTransaction( ).isActive( ))
			{
				threadSession.get( ).save( object);
			}
			else
			{
				beginTransaction( );
				threadSession.get( ).save( object);
				commitOrRollback( );
			}

			return true;
		}
		catch( Exception ex)
		{
			Log.warn( "Ex=" + ex);
			threadRollback.set( true);
		}

		return false;
	}

	// ---------------------------------------------------------------------------------------------

	public static boolean update( Object object)
	{
		Log.debug( object.getClass( ).getSimpleName( ));

		try
		{
			openSession( );

			if( threadSession.get( ).getTransaction( ).isActive( ))
			{
				threadSession.get( ).update( object);
			}
			else
			{
				beginTransaction( );
				threadSession.get( ).update( object);
				commitOrRollback( );
			}

			return true;
		}
		catch( Exception ex)
		{
			Log.warn( "Ex=" + ex);
			threadRollback.set( true);
		}

		return false;
	}

	// ---------------------------------------------------------------------------------------------

	public static boolean delete( Object object)
	{
		Log.debug( object.getClass( ).getSimpleName( ));

		try
		{
			openSession( );

			if( threadSession.get( ).getTransaction( ).isActive( ))
			{
				threadSession.get( ).delete( object);
			}
			else
			{
				beginTransaction( );
				threadSession.get( ).delete( object);
				commitOrRollback( );
			}

			return true;
		}
		catch( Exception ex)
		{
			Log.warn( "Ex=" + ex);
			threadRollback.set( true);
		}

		return false;
	}

	// ---------------------------------------------------------------------------------------------
}